/**
 * Copyright 2011-2011 - Members of the Chaupal Community
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package net.chaupal.Impl.v1.Bucket;

import java.nio.ByteBuffer;
import java.util.Map.Entry;
import net.chaupal.API.v1.Bucket.Bucket;
import net.chaupal.API.v1.Exception.InvalidSizeException;
import net.chaupal.API.v1.Message.MessageNumber;
import net.chaupal.API.v1.Message.MessageType;
import net.chaupal.API.v1.Message.SliceNumber;
import net.chaupal.API.v1.Peer.Hook;
import net.chaupal.API.v1.Peer.PeerID;
import net.chaupal.API.v1.ProtocolVersion1;
import net.chaupal.Impl.v1.ProtocolVersion1Impl_v1;

/**
 * API definition of the bucket concept as described in the Chaupal protocols.
 */
public final class BucketImpl_v1 extends ProtocolVersion1Impl_v1
        implements Bucket {

    private PeerID sourcePeerID = null;
    private PeerID destinationPeerID = null;
    private PeerID nextHop = null;
    private MessageNumber messageNumber = null;
    private SliceNumber sliceNumber = null;
    private MessageType messageType = null;
    private Hook sourceHook = null;
    private Hook destinationHook = null;
    private boolean requiresConfirmation = false;
    private boolean embedded = false;
    private boolean lastSlice = false;
    private boolean propagated = false;
    private boolean sliced = false;
    private boolean meta = false;
    private byte[] content = null;

    @Override
    public final synchronized void setSourcePeerID(PeerID pid) {
        this.sourcePeerID = pid;
    }

    @Override
    public final synchronized void setDestinationPeerID(PeerID pid) {
        this.destinationPeerID = pid;
    }

    @Override
    public final synchronized void setNextHop(PeerID pid) {
        this.nextHop = pid;
    }

    @Override
    public final synchronized void setSourceHook(Hook h) {
        this.sourceHook = h;
    }

    @Override
    public final synchronized void setDestinationHook(Hook h) {
        this.destinationHook = h;
    }

    @Override
    public final MessageType getMessageType() {
        return this.messageType;
    }

    @Override
    public final MessageNumber getMessageNumber() {
        return this.messageNumber;
    }

    @Override
    public final synchronized void setSliceNumber(SliceNumber sn) {
        this.sliceNumber = sn;
    }

    @Override
    public final synchronized void setRequiresConfirmation(boolean rc) {
        this.requiresConfirmation = rc;
    }

    @Override
    public final synchronized void setSliced(boolean sl) {
        this.sliced = sl;
    }

    @Override
    public final synchronized void setLastSlice(boolean ls) {
        this.lastSlice = ls;
    }

    @Override
    public final synchronized void setEmbedded(boolean em) {
        this.embedded = em;
    }

    @Override
    public final synchronized void setPropagated(boolean pr) {
        this.propagated = pr;
    }

    /**
     * {@inheritDoc }
     * 
     * This method exposes the inner byte array.
     *
     * @return the content of this bucket
     */
    @Override
    @SuppressWarnings("ReturnOfCollectionOrArrayField")
    public final byte[] getContent() {
        return this.content;
    }

    @Override
    public final PeerID getSourcePeerID() {
        return this.sourcePeerID;
    }

    @Override
    public final PeerID getDestinationPeerID() {
        return this.destinationPeerID;
    }

    @Override
    public final PeerID getNextHop() {
        return this.nextHop;
    }

    @Override
    public final Hook getSourceHook() {
        return this.sourceHook;
    }

    @Override
    public final Hook getDestinationHook() {
        return this.destinationHook;
    }

    @Override
    public final SliceNumber getSliceNumber() {
        return this.sliceNumber;
    }

    @Override
    public final boolean getRequiresConfirmation() {
        return this.requiresConfirmation;
    }

    @Override
    public final boolean isSliced() {
        return this.sliced;
    }

    @Override
    public final boolean isLastSlice() {
        return this.lastSlice;
    }

    @Override
    public final boolean isEmbedded() {
        return this.embedded;
    }

    @Override
    public final boolean isPropagated() {
        return this.propagated;
    }

    @Override
    public final synchronized int getContentSize() {
        if (this.content == null ) {
            return 0;
        } else {
            return this.content.length;
        }
    }

    /**
     * {@inheritDoc }
     *
     * @param ct bucket content
     * @throws InvalidSizeException if content size is greater than
     * 65535.
     */
    @Override
    @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
    public synchronized final void setContent(byte[] ct)
            throws InvalidSizeException {

        if ( ct != null ) {
            if ( ct.length > 65535 ) {
                final int tempLength = ct.length;
                throw new InvalidSizeException() {

                    @SuppressWarnings("FieldNameHidesFieldInSuperclass")
                    public static final long serialVersionUID
                        = ProtocolVersion1.defaultSerialVersionUID;

                    @Override
                    public int getSize() {
                        return tempLength;
                    }

                };
            }
        }
        
        this.content = ct;

    }

    @Override
    public synchronized final void setMessageType(MessageType mt) {
        this.messageType = mt;
    }

    @Override
    public synchronized final void setMessageNumber(MessageNumber mn) {
        this.messageNumber = mn;
    }

    @Override
    public final boolean isMetaData() {
        return this.meta;
    }

    @Override
    public synchronized final void setMetaData(boolean b) {
        this.meta = b;
    }

    @Override
    public final boolean isUserData() {
        return !this.meta;
    }

    @Override
    public synchronized final void setUserData(boolean b) {
        this.meta = !b;
    }

    @Override
    public byte[] toByteArray() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void writeIntoByteBuffer(ByteBuffer bb, int pos) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Bucket readFromByteBuffer(ByteBuffer bb, int pos) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Entry<String, String> toStringEntry() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Bucket fromStringEntry(Entry<String, String> entry) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

}